﻿using System;
using System.Collections.Generic;
using FrameWork;
using UnityEditor.PackageManager.Requests;
using UnityEngine;

namespace FrameWork
{
    public class UIModule
    {
        private static UIModule _instance;

        public static UIModule Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UIModule();
                }
                return _instance;
            }
        }

        private Camera m_UICamera;
        private Transform m_UIRoot;
        private WindowConfig mWindowConfig;
        private Dictionary<string, WindowBase> m_AllWindowDic = new Dictionary<string, WindowBase>();
        private List<WindowBase> m_AllWindowList = new List<WindowBase>();
        private List<WindowBase> m_VisibleWindowList = new List<WindowBase>();
        private Queue<WindowBase> mWindowStack = new Queue<WindowBase>(); // 队列， 用来管理弹窗的循环弹出

        /**
         * 表示开始弹出堆栈，可以用来处理多种情况，比如：正在出栈中有其他界面弹出，可以直接放到栈内进行弹出 等
         * 用来判断当前UI栈中是否有多余的窗口
         */
        private bool mStartPopStackWndStatus = false;
        public void Initialize()
        {
            m_UICamera = GameObject.Find("UICamera").GetComponent<Camera>();
            m_UIRoot = GameObject.Find("UIRoot").transform;
            mWindowConfig = Resources.Load<WindowConfig>("WindowConfig");
            //在手机上不会触发调用
#if UNITY_EDITOR
            mWindowConfig.GeneratorWindowConfig();
#endif
        }

        #region 窗口管理

        public T PopUpWindow<T>() where T: WindowBase, new()
        {
            System.Type type = typeof(T);
            string windowName = type.Name;
            WindowBase windowBase = GetWindow(windowName);
            if (windowBase != null)
            {
                return ShowWindow(windowName) as T;
            }
            T t = new T();
            return InitializeWindow(t, windowName) as T;
        }

        private WindowBase PopUpWindow(WindowBase window)
        {
            System.Type type = window.GetType();
            string windowName = type.Name;
            WindowBase windowBase = GetWindow(windowName);
            if (windowBase != null)
            {
                return ShowWindow(windowName);
            }
            return InitializeWindow(window, windowName);
        }
        private WindowBase InitializeWindow(WindowBase windowBase, string windowName)
        {
            //生成窗口预制体 TODO 未来使用资源加载框架代替
            GameObject newUIWindow = TempLoadWindow(windowName);
            //初始化
            if (newUIWindow != null)
            {
                windowBase.gameObject = newUIWindow;
                windowBase.transform = newUIWindow.transform;
                windowBase.Canvas = newUIWindow.GetComponent<Canvas>();
                windowBase.Canvas.worldCamera = m_UICamera;
                windowBase.transform.SetAsLastSibling();
                windowBase.Name = newUIWindow.name;
                windowBase.OnAwake();
                windowBase.SetVisible(true);
                windowBase.OnShow();
                RectTransform rectTrans = newUIWindow.GetComponent<RectTransform>();
                rectTrans.anchorMax = Vector2.one;
                rectTrans.offsetMax = Vector2.zero;
                rectTrans.offsetMin = Vector2.zero;
                m_AllWindowDic.Add(windowName, windowBase);
                m_AllWindowList.Add(windowBase);
                m_VisibleWindowList.Add(windowBase);
                SetWindowMaskVisible();
                return windowBase;
            }
            else
            {
                Debug.LogError($"没有加载到对应{windowName}的窗口");
            }
            return null;
        }
        private WindowBase ShowWindow(string windowName)
        {
            WindowBase window = null;
            if (m_AllWindowDic.ContainsKey(windowName))
            {
                window = m_AllWindowDic[windowName];
                if (window.gameObject != null && window.Visible == false)
                {
                    m_VisibleWindowList.Add(window);
                    window.transform.SetAsLastSibling();
                    window.SetVisible(true);
                    SetWindowMaskVisible();
                    window.OnShow();
                }
                return window;
            }
            else
            {
                Debug.LogError($"{windowName}窗口不存在 请调用PopUpWindow弹出");
            }
            return null;
        }
        public WindowBase GetWindow(string windowName)
        {
            if (m_AllWindowDic.ContainsKey(windowName))
                return m_AllWindowDic[windowName];
            return null;
        }
        /**
         * 获取已经弹出的弹窗
         */
        public T GetWindow<T>() where T: WindowBase
        {
            System.Type type = typeof(T);
            foreach (var item in m_VisibleWindowList)
            {
                if (item.Name == type.Name)
                {
                    return (T)item;
                }
            }
            Debug.LogError("该窗口没有获取到: " + type.Name);
            return null;
        }
        public void HideWindow(string wndName)
        {
            WindowBase window = GetWindow(wndName);
            HideWindow(window);
        }
        public void HideWindow<T>() where T: WindowBase
        {
            HideWindow(typeof(T).Name);
        }
        private void HideWindow(WindowBase window)
        {
            if (window != null && window.Visible)
            {
                m_VisibleWindowList.Remove(window);
                window.SetVisible(false);
                SetWindowMaskVisible();
                window.OnHide();
            }
            //在点击窗口右上角的关闭按钮后 会触发出栈逻辑
            //在出栈的情况下，上一个界面隐藏时，自动打开栈中的下一个界面
            AutoPopNextStackWindow(window);
        }

        private void DestroyWindow(string wndName)
        {
            WindowBase window = GetWindow(wndName);
            DestroyWindow(window);
        }
        public void DestroyWindow<T>() where T: WindowBase
        {
            DestroyWindow(typeof(T).Name);
        }
        private void DestroyWindow(WindowBase window)
        {
            if (window != null)
            {
                if (m_AllWindowDic.ContainsKey(window.Name))
                {
                    m_AllWindowDic.Remove(window.Name);
                    m_AllWindowList.Remove(window);
                    m_VisibleWindowList.Remove(window);
                }
                window.SetVisible(false);
                SetWindowMaskVisible();
                window.OnHide();
                window.OnDestroy();
                GameObject.Destroy(window.gameObject);
            }
            //在出栈的情况下，上一个界面隐藏时，自动打开栈种的下一个界面
            AutoPopNextStackWindow(window);
        }
        public void DestroyAllWindow(List<string> filterList = null)
        {
            for (int i = m_AllWindowList.Count - 1; i >= 0; i--)
            {
                WindowBase window = m_AllWindowList[i];
                if (window == null || (filterList != null && filterList.Contains(window.Name)))
                {
                    continue;
                }
                DestroyWindow(window.Name);
                Resources.UnloadUnusedAssets();
            }
        }
        private void SetWindowMaskVisible()
        {
            if (!UISetting.Instance.SINGMASK_SYSTEM)
            {
                return;
            }
            WindowBase maxOrderWndBase = null;
            int maxOrder = 0;
            int maxIndex = 0;
            //1.关闭所有窗口的mask 设置为不可见
            //2.从所有可见窗口中 找到层级最大的窗口 把mask设置为可见
            {

                for (int i = 0; i < m_VisibleWindowList.Count; i++)
                {
                    WindowBase window = m_VisibleWindowList[i];
                    if (window != null && window.gameObject != null)
                    {
                        window.SetMaskVisible(false);
                        if (maxOrderWndBase == null)
                        {
                            maxOrderWndBase = window;
                            maxOrder = window.Canvas.sortingOrder;
                            maxIndex = window.transform.GetSiblingIndex();
                        }
                        else
                        {
                            //找到最大层级的渲染窗口
                            if (maxOrder < window.Canvas.sortingOrder)
                            {
                                maxOrderWndBase = window;
                                maxOrder = window.Canvas.sortingOrder;
                            }
                            //两个窗口渲染层级相同 就找到同一个节点最靠下的物体 优先渲染mask
                            else if (maxOrder == window.Canvas.sortingOrder && maxIndex < window.transform.GetSiblingIndex())
                            {
                                maxOrderWndBase = window;
                                maxOrder = window.transform.GetSiblingIndex();
                            }
                        }
                    }
                }
            }
            if (maxOrderWndBase != null)
            {
                maxOrderWndBase.SetMaskVisible(true);
            }
        }
        //TODO 未来使用资源加载框架代替
        private GameObject TempLoadWindow(string wndName)
        {
            GameObject window = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>(mWindowConfig.GetWindowPath(wndName)), m_UIRoot);
            window.transform.localScale = Vector3.one;
            window.transform.localPosition = Vector3.zero;
            window.transform.rotation = Quaternion.identity;
            window.name = wndName;
            return window;
        }

        #endregion

        #region 堆栈系统

        /// <summary>
        /// 进栈一个界面
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="popCallBack">弹出回调</param>
        public void PushWindowToStack<T>(Action<WindowBase> popCallBack = null) where T: WindowBase, new()
        {
            T windowBase = new T();
            windowBase.PopStackListener = popCallBack;
            mWindowStack.Enqueue(windowBase);
        }

        /// <summary>
        /// 弹出堆栈中第一个弹窗
        /// </summary>
        public void StartPopFirstStackWindow()
        {
            if (mStartPopStackWndStatus) return;
            mStartPopStackWndStatus = true;
            PopStackWindow();
        }

        /// <summary>
        /// 压入并且弹出堆栈弹窗 主要用于UI显示时的自动调用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="popCallBack">弹出回调</param>
        public void PushAndPopStackWindow<T>(Action<WindowBase> popCallBack = null) where T: WindowBase, new()
        {
            PushWindowToStack<T>(popCallBack);
            StartPopFirstStackWindow();
        }
        /// <summary>
        /// 自动弹出堆栈中的下一个窗口 用于UI界面关闭后弹出下一个窗口
        /// </summary>
        /// <param name="windowBase">当前窗口</param>
        public void AutoPopNextStackWindow(WindowBase windowBase)
        {
            if (windowBase != null && mStartPopStackWndStatus && windowBase.PopStackState)
            {
                windowBase.PopStackState = false;
                PopStackWindow();
            }
        }
        /// <summary>
        /// 弹出堆栈弹窗
        /// </summary>
        /// <returns></returns>
        public bool PopStackWindow()
        {
            if (mWindowStack.Count > 0)
            {
                //dequeue获取的是当前窗口
                WindowBase window = mWindowStack.Dequeue();
                //将当前窗口弹出 并更改状态
                WindowBase popWindow = PopUpWindow(window);
                //弹出窗口后 获取弹出的窗口调用弹出回调
                popWindow.PopStackListener = window.PopStackListener;
                popWindow.PopStackState = true;
                popWindow.PopStackListener?.Invoke(popWindow);
                popWindow.PopStackListener = null;
                return true;
            }
            else
            {
                mStartPopStackWndStatus = false;
            }
            return false;
        }
        /// <summary>
        /// 清理队列
        /// </summary>
        public void ClearStackWindows()
        {
            mWindowStack.Clear();
        }

        #endregion


    }
}